package chapter_15
import Math.{E, PI}

// 样本类

sealed abstract class Expr  // 封闭类
// 封闭类除了类定义所在的文件之外不能再添加任何新的子类
case class Var(name: String) extends Expr
case class Number(num: Double) extends Expr
case class UnOp(operator: String, arg: Expr) extends Expr
case class BinOp(operator: String, left: Expr, right: Expr) extends Expr


object Expr {
  def simplifyTop(expr: Expr): Expr = expr match {
    // 模式匹配
    case UnOp("-", UnOp("-", e)) => e     // 双重负号
    case BinOp("+", e, Number(0)) => e    // 加0
    case BinOp("*", e, Number(1)) => e    // 乘1
    case _ => expr
  }

  def tp(expr: Any) {
    // 通配模式
    expr match
    {
      //    case BinOp(op, left, right) => println(expr + " is a binary operation")
      // 忽略对象中不关心的部分
      case BinOp(_, _, _) => println(expr + " is a binary operation")
      case _ =>
    }
  }

  def finalModel(x: Any) = x match {
    // 常量模式
    case 5 => "five"
    case true => "truth"
    case "hello" => "hi!"
    case Nil => "the empty list"
    case _ => "something else"
  }

  def variableModel() =  {
    // 变量模式

    def test01(E: Any) = E match {
      case PI => "strange match? PI = " + PI
      case _ => "OK"
    }

    val pi = PI
    def test02(E: Any) = E match {
      // pi是变量模式，它可以匹配任意输入
//      case pi => "strange match? PI = " + pi  // 变量
      case `pi` => "strange match? PI = " + pi  // 常量
      case _ => "OK"
    }

//    println(test01(E))
    println(test02(E))
  }

  def constructorModel(x: Any) = x match {
    // 构造器模式
    case BinOp("+", e, Number(0)) => println("a deep match")
    case _ =>
  }

  def iterModel(x: Any) = x match {
    // 序列模式
    case List(0, _, _) => println("found it")
//    case List(0, _*) => println("found it") // 匹配一个不指定长度的序列
    case _ =>
  }

  def tupleModel(x: Any): Unit = x match {
    // 元组模式
    case (a, b, c) => println("matched " + a + b + c)
    case _ =>
  }

  def typeModel(x: Any) = x match {
    // 类型模式
    case s: String => println(s.length)
    case m: Map[_, _] => println(m.size)
    case _ =>
  }

//  def typeClearModel(x: Any): Unit = x match {
//    // 类型擦除
//    case m: Map[Int, Int] => println("yes")
//    case _ => println("no")
//  }

  def isStringArray(x: Any) = x match {
      // 数组不存在类型擦除
    case a: Array[String] => println("array yes")
    case _ => println("array no")
  }

  def variableBind(x: Any): Unit = x match {
    // 变量绑定
    // UnOp("abs", _)绑定到变量e上
    case UnOp("abs", e @ UnOp("abs", _)) => println(e)
    case _ =>
  }

  def simplifyAdd(e: Any) = e match {
    // 模式守卫
    // scala要求模式是线性的：模式变量仅允许在模式中出现一次。
//    case BinOp("+", x, x) => BinOp("*", x, Number(2)) // error
    case BinOp("+", x, y) if x == y =>    // 仅匹配x等于y的模式
      BinOp("*", x, Number(2))
    case e: Int if 0 < e =>  "正整数匹配到了" // 仅匹配正整数
    case e: String if e(0) == 'a' => "a开始的字符串匹配到了"   // 仅匹配以字母a开始的字符串
    case _ => e
  }

  def simplifyAll(expr: Expr): Expr = expr match {
      // 模式重叠
    case UnOp("-", UnOp("-", e)) => simplifyAll(e)  // ‘-’是自身的反转
    case BinOp("+", e, Number(0)) => simplifyAll(e) // ‘0’对于+来说不改变结果
    case BinOp("*", e, Number(1)) => simplifyAll(e)// ‘1’对于*来说不改变结果
    case UnOp(op, e) => UnOp(op, simplifyAll(e))
    case BinOp(op, l, r) => BinOp(op, simplifyAll(l), simplifyAll(r))
    case _ => expr
  }

  def describe(e: Expr): String = (e: @unchecked) match {
    // 注解
    case Number(_) => "a number"
    case Var(_) => "a variable"
  }

  def showOption(x: Option[String]) = x match {
    // Option类型
    case Some(s) => println(s)
    case None => println("?")
  }

  def partialFunction(): Unit = {
    // 用作偏函数的样本序列
    val second: List[Int] => Int = {
      case x :: y :: _ => y
    }
    println(second(List(5, 6, 7)))
//    println(second(List())) // 错误

    val second2: PartialFunction[List[Int], Int] = {
      case x :: y :: _ => y
    }
    // 测试是否函数对某个特定值有定义
    println(second2.isDefinedAt(List(5, 6, 7)))
    println(second2.isDefinedAt(List()))
    println(second2(List(5, 6, 7)))
  }

  def forMatch(): Unit = {
    // for表达式里的模式
    val results = List(Some("apple"), None, Some("orange"))
    for (Some(fruit) <- results) println(fruit)
  }

  def main(args: Array[String]): Unit = {
//    val v = Var("x")
//    val op = BinOp("+", Number(1), v)
//    println(op)

    // 样本类参数列表中的所有参数都隐式获得了val前缀
//    println(v.name)
//    println(op.left)

    // 样本类添加了方法toString、hashCode和equals的“自然实现”
//    println(op.right == Var("x"))

    // 模式匹配
//    val up: Expr = UnOp("-", UnOp("-", Number(10)))
//    println(simplifyTop(up))

    // 通配模式
//    tp(BinOp("hello", Number(1), Number(2)))

    // 常量模式
//    println(finalModel(Nil))

    // 变量模式
//    variableModel()

    // 构造器模式
//    constructorModel(BinOp("+", Number(1), Number(0)))

    // 序列模式
//    iterModel(List(0, 2, 3))

      // 元组模式
//    tupleModel(("a ", 3, "tuple"))

    // 类型模式
//    typeModel("hello")
//    typeModel(Map(1 -> 'a', 2 -> 'b'))

    // 类型擦除
//    typeClearModel(Map(1 -> 1))
//    typeClearModel(Map("head" -> "10"))
//    isStringArray(Array("abc"))
//    isStringArray(Array(1, 2, 3))

    // 变量绑定
//    variableBind(UnOp("abs", UnOp("abs", Var("x"))))

    // 模式守卫
//    println(simplifyAdd(10))
//    println(simplifyAdd("apple"))
//    println(simplifyAdd(BinOp("+", Number(2), Number(2))))

    // Option类型
//    val mp = Map("Japan" -> "Tokyo", "China" -> "Beijing")
//    showOption(mp get "Japan")
//    showOption(mp get "UK")

    // 模式无处不在
//    partialFunction()

    // for表达式里的模式
    forMatch()
  }
}